import Event from "sap/ui/base/Event";
import Filter from "sap/ui/model/Filter";
import FilterOperator from "sap/ui/model/FilterOperator";
import ListBinding from "sap/ui/model/ListBinding";
import SearchField from "sap/m/SearchField";
import Sorter from "sap/ui/model/Sorter";
import Table from "sap/m/Table";
import ViewSettingsDialog from "sap/m/ViewSettingsDialog";
import ViewSettingsItem from "sap/m/ViewSettingsItem";

import { BaseController } from "sap/ui/demo/nav/controller/BaseController";
import HashChanger from "sap/ui/core/routing/HashChanger";
import ListItemBase from "sap/m/ListItemBase";
import {
  EmployeeOverviewRouteArgs,
  EmployeeResumeRouteArgs,
} from "sap/ui/demo/nav/interfaces/IEmployee.controller";

/**
 * @namespace sap.ui.demo.nav.controller.employee.overview
 */
export default class EmployeeOverviewContent extends BaseController {
  private oTable: Table | null = null;
  private oVSD: ViewSettingsDialog | null = null;

  private sSortField = "";
  private bSortDescending = false;
  private aValidSortFields = ["EmployeeID", "FirstName", "LastName"];
  private sSearchQuery = "";
  private oRouteArgs: EmployeeOverviewRouteArgs = {
    "?query": {
      search: "",
      sortField: this.aValidSortFields[0],
      sortDescending: false,
      showDialog: false,
    },
  };

  onInit(): void {
    console.info("EmployeeOverviewContent init...");

    this.oTable = this.byId("employeesTable") as Table;
    this.oVSD = new ViewSettingsDialog("vsd", {
      confirm: (oEvent) => {
        const oSortItem = oEvent.getParameter("sortItem") as ViewSettingsItem;
        this.oRouteArgs["?query"].sortField = oSortItem.getKey();
        this.oRouteArgs["?query"].sortDescending =
          oEvent.getParameter("sortDescending");
        this.router.navTo("employeeOverview", this.oRouteArgs, {}, true);
      },
      cancel: () => {
        this.oRouteArgs["?query"].showDialog = false;
        this.router.navTo("employeeOverview", this.oRouteArgs, {}, true);
      },
    });

    this._initViewSettingsDialog();
  }

  onBeforeRendering(): void {
    console.log("EmployeeOverviewContent.onBeforeRendering");
    this._syncSearchAndSort();
    this._syncShowDialogBox();
  }

  private _syncSearchAndSort() {
    const sCurrentHash = HashChanger.getInstance().getHash();
    const routeInfo = this.router.getRouteInfoByHash(sCurrentHash);

    //@ts-ignore
    this.oRouteArgs = routeInfo?.arguments || {};

    this.oRouteArgs["?query"] = this.oRouteArgs["?query"] || {
      sortDescending: false,
      sortField: this.aValidSortFields[0],
      search: "",
      showDialog: false,
    };

    const oQuery = this.oRouteArgs["?query"];
    this._applySearchFilter(oQuery.search);
    this._applySorter(oQuery.sortField, oQuery.sortDescending);
  }

  private _syncShowDialogBox() {
    const oQuery = this.oRouteArgs["?query"];
    if (
      (typeof oQuery.showDialog === "boolean" && oQuery.showDialog) ||
      (typeof oQuery.showDialog === "string" && oQuery.showDialog === "true")
    ) {
      this.oVSD?.open();
    }
  }

  private _initViewSettingsDialog() {
    this.oVSD
      ?.addSortItem(
        new ViewSettingsItem({
          key: "EmployeeID",
          text: "Employee ID",
          selected: true,
        })
      )
      .addSortItem(
        new ViewSettingsItem({
          key: "FirstName",
          text: "First Name",
          selected: false,
        })
      )
      .addSortItem(
        new ViewSettingsItem({
          key: "LastName",
          text: "Last Name",
          selected: false,
        })
      );
  }

  onItemPressed(oEvent: Event) {
    const oListItem = oEvent.getParameter("listItem") as ListItemBase;
    const oCtx = oListItem.getBindingContext();
    this.router.navTo("employeeResume", {
      employeeId: oCtx?.getProperty("EmployeeID"),
      "?query": { tab: "Info" },
    } as EmployeeResumeRouteArgs);
  }

  onSortButtonPressed() {
    this.oRouteArgs["?query"].showDialog = true;
    this.router.navTo("employeeOverview", this.oRouteArgs);
  }

  onSearchEmployeesTable(oEvent: Event) {
    const sSearch = (oEvent.getSource() as SearchField).getValue();
    this.oRouteArgs["?query"].search = sSearch;
    this.router.navTo("employeeOverview", this.oRouteArgs, {}, true);
  }

  /**
   * Applies sorting on our table control
   * @param sSortField  the name of the field used for sorting
   * @param sortDescending true or false as a string or boolean value to specify a descending order
   * @returns
   */
  private _applySorter(sSortField: string, sortDescending: boolean | string) {
    let bSortDescending = false;

    // convert the sort order to a boolean value
    if (sSortField && this.aValidSortFields.includes(sSortField)) {
      if (typeof sortDescending === "string")
        bSortDescending = sortDescending === "true";
      else if (typeof sortDescending === "boolean")
        bSortDescending = sortDescending;
    }

    // sort only if the sorter has changed
    if (
      this.sSortField &&
      this.sSortField === sSortField &&
      this.bSortDescending === bSortDescending
    )
      return;

    this.sSortField = sSortField;
    this.bSortDescending = bSortDescending;
    const oSorter = new Sorter(sSortField, bSortDescending);

    // sync with View Settings Dialog
    this.oVSD
      ?.setSelectedSortItem(sSortField)
      .setSortDescending(bSortDescending);

    const oBinding = this.oTable?.getBinding("items") as ListBinding;
    oBinding.sort(oSorter);
  }

  private _applySearchFilter(sSearchQuery: string) {
    if (this.sSearchQuery === sSearchQuery) return;

    this.sSearchQuery = sSearchQuery;
    (this.byId("searchField") as SearchField).setValue(sSearchQuery);

    // add filters for search
    let oFilter: Filter | null = null;
    if (sSearchQuery?.length > 0) {
      const firstNameFilter = new Filter(
        "FirstName",
        FilterOperator.Contains,
        sSearchQuery
      );
      const lastNameFilter = new Filter(
        "LastName",
        FilterOperator.Contains,
        sSearchQuery
      );

      // create filter object
      const aFilters = [firstNameFilter, lastNameFilter];
      oFilter = new Filter({ filters: aFilters, and: false });
    } else {
      oFilter = null;
    }

    // update list binding
    const oBinding = this.oTable?.getBinding("items") as ListBinding;
    oBinding.filter(oFilter || []);
  }
}
